package com.gds.service.impl;


import com.gds.common.wechat.wechat.WxJSUtil;
import com.gds.common.wechat.wechat.WxPayUtil;
import com.gds.common.wechat.wechat.XMLUtil;
import com.gds.common.wechat.wechat.constants.Ticket;
import com.gds.common.wechat.wechat.constants.WechantConstant;
import com.gds.common.wechat.wechat.entities.*;
import com.gds.common.wechat.wechat.enums.ReturnCodeEnum;
import com.gds.common.wechat.wechat.enums.WechatPayTradeTypeEnum;
import com.gds.common.wechat.wechat.httpRequest.WechatCgiHttpRequest;
import com.gds.common.wechat.wechat.httpRequest.WechatOath2HttpRequest;
import com.gds.common.wechat.wechat.httpRequest.WechatPayHttpRequest;
import com.gds.service.WechatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

@Service
public class WechatServiceImpl implements WechatService {
    private Logger log = LoggerFactory.getLogger(WechatServiceImpl.class);

    @Resource
    private WxProperties wxProperties;

    /***
     * 微信公众号支付 接口
     * @param orderCode  订单号
     * @param money 支付钱数 单位人民币(分)
     * @param clientIp 请求用户 ip
     * @param openId 微信openId ip
     * @throws Exception
     */
    @Override
    public Map<String, Object> unifiedorderJSAPI(String orderCode,
                                                 int money,
                                                 String clientIp,
                                                 String openId
    ) throws Exception {
        Map<String, Object> result = new HashMap<>(3);
        result.put("errno", "300");
        UnfiedOrderParam unfiedOrderParam = new UnfiedOrderParam();
        unfiedOrderParam.setAppid(wxProperties.getAppId());
        unfiedOrderParam.setMch_id(wxProperties.getMchId());
        unfiedOrderParam.setBody("美客威餐饮--支付");
        unfiedOrderParam.setTotal_fee(money);
        unfiedOrderParam.setFee_type("CNY");
        unfiedOrderParam.setSpbill_create_ip(clientIp);
        unfiedOrderParam.setNotify_url(wxProperties.getNotifyUrl());
        unfiedOrderParam.setOpenid(openId);
        unfiedOrderParam.setTrade_type(WechatPayTradeTypeEnum.公众号支付.getCode());
        unfiedOrderParam.setOut_trade_no(orderCode);
        UnfiedOrderResult UnfiedOrderResult = WechatPayHttpRequest.unifiedorder(unfiedOrderParam, wxProperties.getApi_key());
        Long timestamp = System.currentTimeMillis() / 1000;
        //返回状态码  处理
        if (ReturnCodeEnum.失败.getCode().equals(UnfiedOrderResult.getReturn_code())) {
            result.put("msg", UnfiedOrderResult.getReturn_msg());
            return result;
        }
        if (ReturnCodeEnum.成功.getCode().equals(UnfiedOrderResult.getReturn_code()) && ReturnCodeEnum.失败.getCode().equals(UnfiedOrderResult.getResult_code())) {
            result.put("msg", UnfiedOrderResult.getErr_code_des());
            result.put("errno", UnfiedOrderResult.getErr_code());
            return result;
        }
        if (ReturnCodeEnum.成功.getCode().equals(UnfiedOrderResult.getReturn_code()) && ReturnCodeEnum.成功.getCode().equals(UnfiedOrderResult.getResult_code())) {
            result.put("msg", "200");
            result.put("errno", "200");
            Map<String, Object> data = new HashMap<>();
            data.put("timeStamp", timestamp+"");
            data.put("nonceStr", timestamp+"");
            data.put("package", "prepay_id="+UnfiedOrderResult.getPrepay_id());
            data.put("signType", "MD5");
            data.put("appId", UnfiedOrderResult.getAppid());



            SortedMap<Object, Object> params = new TreeMap<Object, Object>();
            params.put("appId", UnfiedOrderResult.getAppid());
            params.put("signType","MD5");
            params.put("package", "prepay_id="+UnfiedOrderResult.getPrepay_id());
            params.put("nonceStr", timestamp+"");
            params.put("timeStamp",timestamp+"");
            log.info("生成sign 参数"+params.toString());
            String sign = WxPayUtil.createSign("UTF-8", params, wxProperties.getApi_key());
            log.info("返回的appid:"+UnfiedOrderResult.getAppid());
            log.info("返回的package:"+"prepay_id="+UnfiedOrderResult.getPrepay_id());
            log.info("返回的timeStamp:"+"timeStamp="+timestamp);
            log.info("生成sign:"+sign);

            data.put("paySign",sign);

            result.put("data", data);
            return result;
        }
        return result;
    }


    public UserInfoResult getWechatUserInfo(String code) throws UnsupportedEncodingException {
        //todo 获取 access_token
        Oauth2AccessTokenResult accessToken = getAccessToken(code);
        if (getAccessToken(code) == null) {
            //注意处理重新授权
            return null;
        }
        String access_token = accessToken.getAccess_token();
        String openid = accessToken.getOpenid();
        String refresh_token = accessToken.getRefresh_token();
        //todo 查验 access_token 是否有效
        //todo  无效 刷新 access_token token
        if (!WechatOath2HttpRequest.checkAccessToken(access_token, openid)) {
            accessToken = WechatOath2HttpRequest.toRefreshToken(wxProperties.getAppId(), "refresh_token", refresh_token);
            access_token = accessToken.getAccess_token();
            openid = accessToken.getOpenid();
            refresh_token = accessToken.getRefresh_token();
        }
        //TODO 获取用户信息
        UserInfoResult UserInfo = WechatOath2HttpRequest.userInfo(access_token, openid, "zh_CN");
        return UserInfo;
    }

    /***
     * auth  获取access_token
     * @param code
     * @return
     */
    @Override
    public Oauth2AccessTokenResult getAccessToken(String code) {
        //todo 获取 access_token
        Oauth2AccessTokenResult accessToken = WechatOath2HttpRequest.oauth2AccessToken(wxProperties.getAppId(), wxProperties.getAppsecret(), code, "authorization_code");
        if (200 != (accessToken.getCode())) {
            //注意重新授权
            return null;
        } else {
            return accessToken;
        }
    }

    /***
     * 获取 js引用配置
     * @param url
     * @return
     */
    @Override
    public Map<String, Object> getJsConfig(String url) {
        Map<String, Object> result = new HashMap<>(3);
        result.put("errno", "300");
        //检查 ticket是否过期
        Map<String, Object> check = getTicket(wxProperties.getAppId(), wxProperties.getAppsecret());
        if (!"200".equals(check.get("errno"))) {
            result.put("msg", check.get("msg"));
            return result;
        }
        //获取 配置信息
        Map<String, String> config = WxJSUtil.sign(url, WechantConstant.ticket.value);
        config.put("appId", wxProperties.getAppId());
        result.put("errno", "300");
        result.put("data", config);
        return result;
    }


    /***
     * 检查更新 ticket
     * @param appId
     * @param secretkey
     * @return
     */
    private Map<String, Object> getTicket(String appId, String secretkey) {
        Map<String, Object> result = new HashMap<>(3);
        result.put("errno", "300");
        if (WechantConstant.ticket == null || System.currentTimeMillis() > WechantConstant.ticket.getOverdue()) {
            synchronized (WechatServiceImpl.class) {
                if (WechantConstant.ticket == null || System.currentTimeMillis() > WechantConstant.ticket.getOverdue()) {
                    //获取 access_token
                    CgiAccessTokenResult token = WechatCgiHttpRequest.getToken("client_credential", appId, secretkey);
                    if (200 != token.getCode()) {
                        result.put("msg", token.getErrmsg());
                        return result;
                    }
                    Ticket accessToken = new Ticket();
                    accessToken.setValue(token.getAccess_token());
                    accessToken.setOverdue(token.getExpires_in() * 1000 + System.currentTimeMillis());
                    accessToken.setExpire(token.getExpires_in());
                    WechantConstant.accessToken = accessToken;
                    // 获取 ticket
                    CgiTicketResult ticket = WechatCgiHttpRequest.getTicket(token.getAccess_token());
                    if (200 != ticket.getCode()) {
                        result.put("msg", ticket.getErrmsg());
                        return result;
                    }
                    Ticket ticket1 = new Ticket();
                    ticket1.setValue(ticket.getTicket());
                    ticket1.setOverdue(ticket.getExpires_in() * 1000 + System.currentTimeMillis());
                    ticket1.setExpire(ticket.getExpires_in());
                    WechantConstant.ticket = ticket1;
                }
            }

        }
        result.put("errno", "200");
        return result;

    }

    @Override
    public void wxPayStatus(HttpServletRequest request, HttpServletResponse response) throws Exception {

        //从流中读取参数
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();

        //读取到的是xml,需要解析成map
        Map<String, String> map = new HashMap<>();
        map = XMLUtil.doXMLParse(sb.toString());
        //过滤空值,得到一个没有空值的treemap
        SortedMap<Object, Object> packageparams = new TreeMap<>();
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String parameter = iterator.next();
            String parameterValue = map.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageparams.put(parameter, v);
        }

        //获取微信支付的api秘钥
        String key = wxProperties.getApi_key();
        log.info("签名验证 :" + sb.toString());
        log.info("签名验证 :" + packageparams.toString());
        //todo
        //验证签名是否正确
        if (WxPayUtil.isTenpaySign("UTF-8", packageparams, key)) {
            /**
             * 处理业务
             */
            String resXml = "";
            if ("SUCCESS".equals((String) packageparams.get("result_code"))) {
                //支付成功
                String app_id = (String) packageparams.get("appid");
                String mch_id = (String) packageparams.get("mch_id");
                String attach = (String) packageparams.get("attach");
                String out_trade_no = (String) packageparams.get("out_trade_no");
                String total_fee = (String) packageparams.get("total_fee");
                String transaction_id = (String) packageparams.get("transaction_id");
                String time_end = (String) packageparams.get("time_end");
                /*************************************************************
                 * 修改订单状态,并向中控传输订单信息
                 *
                 * 此处处理业务逻辑
                 *************************************************************/

                /*************************************************************
                 *        业务逻辑结束                                        *
                 *                                                           *
                 *************************************************************/

                resXml = "<xml>" + "<return_code>SUCCESS</return_code>" + "<return_msg>OK</return_msg>" + "</xml>";
            } else {
                resXml = "<xml>" + "<return_code><!CDATA[FAIL]></return_code>" + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
            }
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        } else {
            //签名验证失败
            log.info("签名验证失败 :" + sb.toString());
        }
    }
}
